Log In  
[back to top]

[ :: Read More :: ]

Cart #dragondeity-0 | 2022-11-24 | Code ▽ | Embed ▽ | No License
11

One last chiptune. I hope you like it! πŸ˜€

P#121318 2022-11-24 14:19 ( Edited 2022-12-19 12:23)

[ :: Read More :: ]

Cart #thegodhandisreal-1 | 2022-11-22 | Code ▽ | Embed ▽ | No License
10

One more! πŸ˜…

P#121148 2022-11-22 03:20 ( Edited 2022-11-22 14:29)

[ :: Read More :: ]

Cart #aurapower-0 | 2022-11-21 | Code ▽ | Embed ▽ | No License
18

Hi everyone, I wrote this song over the weekend, I hope you like it! πŸ˜€

P#121087 2022-11-21 00:44

[ :: Read More :: ]

Cart #downstreamdream-2 | 2023-01-14 | Code ▽ | Embed ▽ | No License
72

UPDATE 1/14/2023, v1.1:
This update couldn’t have happened without @thisismypassword’s contributions to the community. I recently began overhauling my build pipeline for future projects, and one of the first features I added was Shrinko8. Since Downstream Dream is my only project to use the full build pipeline, I used it for testing output from the new minifier, which led to some token golfing. Thanks to this tip, also by @thisismypassword, I was able to free up about 100 tokens! Changes include:

  • Midboss section contains more action and a couple new sprites/sfx
  • Rocks spawn gradually at the start of each lap (so you don’t crash into them immediately after winning the midboss section)
  • Turtle hit/hurtbox size reduced
  • Speed gauge colors changed to represent the danger level of being ejected
  • Slight gfx adjustments
  • Faster boot time

While I have your attention, I’d like to thank everyone who supported this game and said nice things about it, it means so much to me and it made my whole year! Special thanks to @extar, who recently featured it on his Pico Playtime: Best of 2022 video, and extra special thanks to @zep for featuring it on the front page on day one. It’s a huge honor to be listed among so many incredible projects from the community and I’m grateful beyond words to everyone here!

Anyway, if you liked the original release, I hope you enjoy the update!

UPDATE 06/11/2022, OST
I've added a special OST cart for the itch.io download, where you can select music from the soundtrack and watch the game play itself while you listen. I hope you enjoy it!)


Hi everyone,

Here's my new game. It's called Downstream Dream, it's a side-scroller that I guess is somewhere between kart racers and shoot-em-ups. I hope you like it!

It's also published on itch.io if you'd like to support it. Most of the content from that page is duplicated below, but first, a few thanks to BBS members:

  • To @zep, @Makke, @Felice, @Nodepond, and @pahammond for their code contributions to the community, some of which I wouldn't have been able to release this cart anytime soon without! (listed below)

  • To @freds72 and @johanp for their advice. This game would have been a lot worse if not for their kindness and willingness to help a stranger.

  • To @Liquidream for playtesting, and for lots of encouragement when I felt like giving up.

  • To everyone in the Pico-8 community. I'm very grateful that so many are willing to share your creativity and kindness with others. Trading knowledge and games with you all has brought me a lot of joy.

Thank you all!

Game Controls


Legend:

β¬…οΈβž‘οΈβ¬†οΈβ¬‡οΈ = D-Pad or Keyboard Arrow Keys

πŸ…ΎοΈ = Button 1 or Keyboard Z

❎ = Button 2 or Keyboard X

Movement:

⬅️ + πŸ…ΎοΈ - Paddle counter-clockwise

➑️ + πŸ…ΎοΈ - Paddle clockwise

⬆️ + πŸ…ΎοΈ - Steady ahead

⬇️ - Move backwards (with motor)

Offense/Defense:

❎ - Throw

How to Play


From the Developer


My mom loved both adventure and the American southwest; she traveled there many times over her life, and her home was filled with art and souvenirs she'd collected from her visits to the region.

When I was about seven years old, my parents rented a minivan and took me on a long roadtrip across the United States. I don’t remember a lot from that trip other than staring out the window while the landscape slowly changed from cities and farmland, to mountains, to desert, but one memory stands out from the endless monotony of the road; a stop at the Grand Canyon where my mom went white water rafting.

My dad never learned how to swim, and someone needed to watch me anyway, so the two of us waited downstream in the hot afternoon sun, looking for mom's boat to come in. I don’t think the water was particularly rough at that time of year; but like my dad, I’ve never been good at swimming either, and I spent most of the time thinking about how scary the water looked to me. I imagined how if I was on the boat with mom, I would probably fall out and be carried away by the river. She seemed very bold and brave that day!

A couple years before she left this world, mom offered to take me on a trip out west; possibly to Las Vegas, or maybe the Grand Canyon. I politely turned her down for some made-up reason, while the real one probably had something to do with still being in my 20s and wrongly believing that I was too cool to go on vacation with my mother. As a young adult, I assumed that there would always be more time with the people in my life. Now that I'm a little older, I'm learning that there is rarely ever enough. I don’t know where we might have gone or what we might have done on that trip, if I hadn't foolishly said no; but sometimes, it’s nice to dream about it.

Anyway, I hope you enjoy the game. It contains a lot of love, a little regret, and the best game I could make with Pico-8.

-ridgek

Credits and Thanks


External Libraries:

Playtesters:

Special Thanks To:

P#112916 2022-06-09 01:13 ( Edited 2023-03-19 06:09)

[ :: Read More :: ]

Hi everyone,

My new project uses massive tables of graphics metadata, so I've written a new table serializer inspired by this pull request on @BenWiley4000's pico8-table-string to get the job done. Hopefully someone else finds this useful, too!

It uses less characters to store your table as a string than pico8-table-string does (to take up less character / compressed space), but at the cost of 14 more tokens to deserialize, and possibly with less reliability. (It will break if the table contains a string a certain character sequence, see below.) You should also run the output through something like Zep's escape_binary_string before saving to code.

Supported:

  • string/number/boolean values
  • key/value pairs
  • consecutive indexed values starting from 1

Not supported:

  • 0-indexed values
  • non-consecutive indexed values
  • strings containing the ascii sequence \3\120\23

Writing parsers is not one of my strengths, so pull requests on the GitHub repo are open and appreciated!

serialize

---serialize lua table to string
--@param {table} tbl
--  input table
--
--@returns {string}
--  serialized table
function tbl_serialize(tbl)
    local function encode_value(value)
        --ascii unit separator
        --delimits number
        local value_token = "\31"

        --ascii acknowledge
        --delimits true boolean
        local bool_true = "\6"

        --ascii negative acknowledge
        --delimits false boolean
        local bool_false = "\21"

        --ascii start of text
        --delimits start of string
        local str_token = "\2"

        --end of string sequence
        --ascii end of text + x
        --ascii end of transmission block
        local str_end_token = "\3x\23"

        --asci group separator
        --delimits start of table
        local tbl_token = "\29"

        if type(value) == "boolean" then
            return value and bool_true or bool_false

        elseif type(value) == "string" then
            --check for
            --ascii control chars
            for i = 1, #value do
                if ord(sub(value, i, i)) < 32 then
                    --delimit binary string
                    return str_token .. value .. str_end_token
                end
            end

            --encode regular string
            return value_token .. value

        elseif type(value) == "table" then
            return tbl_token .. tbl_serialize(value)
        end

        return value_token .. value
    end

    local str = ""

    --ascii record separator
    --delimits table key
    local key_token = "\30"

    --ascii end of medium
    --delimits end of table
    local tbl_end_token = "\25"

    --get indexed values
    for _, v in ipairs(tbl) do
        str = str .. encode_value(v)
    end

    --get keyed values
    for k, v in pairs(tbl) do
        if type(k) ~= "number" then
            str = str .. key_token .. k .. encode_value(v)
        end
    end

    str = str .. tbl_end_token

    return str
end

---validate output
--@usage
--  output = tbl_serialize(my_table)
--
--  tbl_serialize_validate(
--      my_table,
--      tbl_deserialize(output)
--  )
--
--@param {table} tbl1
--  input table
--
--@param {table} tbl2
--  output table
function tbl_serialize_validate(tbl1, tbl2)
    for k, v in pairs(tbl1) do
        if type(v) == "table" then
            tbl_serialize_validate(tbl2[k], v)
        else
            assert(
                tbl2[k] == v,
                tostr(k) .. ": " .. tostr(v) .. ": " .. tostr(tbl2[k])
            )
        end
    end
end

deserialize

---deserialize table
--@param {string} str
--  serialized table string
--
--@returns {table}
--  deserialized table
function tbl_deserialize(str)
    ---get encoded value
    --@param {string} str
    --  serialized table string
    --
    --@param {integer} i
    --  position of
    --  current delimiter
    --  in serialized table string
    local function get_value(str, i)
        local
            char,
            i_plus1
            =
            sub(str, i, i),
            i + 1

        --table
        if char == "\29" then
            local
                tbl,
                j
                =
                tbl_deserialize(
                    sub(str, i_plus1)
                )

            return tbl, i + j

        --binary string
        elseif char == "\2" then
            for j = i_plus1, #str do
                if sub(str, j, j + 2) == "\3x\23" then
                    return sub(str, i_plus1, j - 1), j + 2
                end
            end

        --bool true
        elseif char == "\6" then
            return true, i

        --bool false
        elseif char == "\21" then
            return false, i
        end

        --number, string,
        --or table key
        --("\30" or "\31")
        for j = i_plus1, #str do
            if ord(sub(str, j, j)) < 32 then
                local value = sub(str, i_plus1, j - 1)

                return tonum(value) or value, j - 1
            end
        end
    end

    local
        tbl,
        i
        =
        {},
        1

    --loop start
    ::parse::

    local char = sub(str, i, i)

    --end of table
    if char == "\25" then
        return tbl, i

    --table key
    elseif char == "\30" then
        local key, j = get_value(str, i)
        local value, k = get_value(str, j + 1)

        tbl[key] = value

        i = k + 1

    --value
    elseif ord(char) < 32 then
        local value, j = get_value(str, i)

        add(tbl, value)

        i = j + 1
    end

    --loop end
    goto parse

    return tbl
end

usage

--example table
tbl1 = {
    true,
    false,
    3,
    "four",
    "binarystring\31\30\6\21\\2\3\23\4\0",
    foo = "bar",
    {
        true,
        false,
        3,
        "four",
        "binarystring\31\30\6\21\\2\3\23\4\0",
        foo = "bar",
        {
            true,
            false,
            3,
            "four",
            "binarystring\31\30\6\21\\2\3\23\4\0",
            foo = "bar"
        }
    }
}

--serialize
str = tbl_serialize(tbl1)

--deserialize
tbl2 = tbl_deserialize(str)

--validate
tbl_serialize_validate(tbl1, tbl2)

--output
printh(escape_binary_str(str), "@clip")

P#112705 2022-06-04 00:46

[ :: Read More :: ]

I don't feel like I have the greatest grasp on Lua metatables/metamethods, but I came across some unexpected behavior this week and was wondering if this is a bug. Example cart attached.

I'm setting up a "class" like so:

class = {}
class.__index = class

function class:new(instance)
    local instance = instance or {}

    setmetatable(instance, self)
    instance.__index = instance

    add(self, instance)

    return instance
end

To save tokens, and since I never expect to have numeric indexes in class or any subclasses I instantiate from it, I simply add the instance to whatever object is self when :new() is called. ie, class[1] is a subclass, and subclass[1] == class[1][1].

This works great if I use vanilla Lua ipairs() to iterate over subclass, but if I use Pico-8's all() or foreach() built-ins, things start breaking. Unlike with ipairs(), if #subclass < #class, the loop continues and retrieves any remaining values from class! So, in the example below, the all() loop will correctly access class[1][1].foo on the first iteration, but instead of stopping, it will then try to access class[2].foo.

EDIT: Forgot to mention, #class[1][1] / #subclass1 and/or count(class[1][1]) / count(subclass1) report the expected counts, so a C-style for loop would also work.

subclass1 = class:new()
subclass2 = class:new()

subclass1:new({ foo = "bar" })

-- assertion passes
for _, instance in ipairs(subclass1) do
    assert(instance.foo)
end

-- assertion fails
for instance in all(subclass1) do
    assert(instance.foo)
end

I don't mind using ipairs(), but since it does cost an extra token, I'm hoping this is a bug!

Cart #yujisogeba-0 | 2022-03-11 | Code ▽ | Embed ▽ | No License

P#108418 2022-03-11 03:55 ( Edited 2022-03-11 09:06)

[ :: Read More :: ]

EDIT: See the first reply below if you'd rather compile and use the native tool, which does seem more streamlined!

Hi, friends!

I just put Pico-8 on my Raspberry Pi for the first time and ran into problems getting my USB gamepads to work. Unfortunately, there's no ARM build for the General Arcade SDL2 Gamepad Tool, and I didn't want to bother with compiling the native helper, so I had to take this manual route. This will only take you a couple minutes.

The final SDL string will look something like this:


First, let's get the GUID.

This issue in the GameControllerDB repo tells us a little bit about the GUID structure in SDL 2.0.5+. It varies between operating systems, and so if you copied it from a different OS to Raspbian, this might be the cause of your woes (as it was mine)!

Open a terminal and run:

$ cat /proc/bus/input/devices

You should see your device listed in the output. We'll be concerned with the three circled values in the sysfs path, and also the version number above it. We'll come back to this output later for the name and input device path:

Convert the endianness of the three syspath IDs, and append the version. (Swap the first two characters with the last two and add four 0s). So for my gamepad:

  • 0003 = 03000000
  • 081f = 1f080000
  • e401 = 01e40000
  • 0110 = 10010000

and the end result: 030000001f08000001e4000010010000

I'm not sure if case matters here, but I went with all lowercase since I know it works.


I tried different names and SDL doesn't seem to care what you call the gamepad, but I went with the weirdo name I was provided, extra spaces and all:


Finally, let's get our mappings. Install jstest if you don't have it:

$ sudo apt update
$ sudo apt install jstest

And also refer to the Handler section in our original output to know which input device to pass to jstest.

For me, it's js0, so I'll pass /dev/input/js0 to jstest:

$ jstest --normal /dev/input/js0

The output looks like this, and is interactive. Each switch should flip when you push a button on the gamepad. Be sure to note the corresponding axis or button numbers.

Now that we know what button is what, we just need to add them to our config string. SDL assumes an Xbox-like gamepad layout. Together with the standard Pico-8 layout it will be mapped like this, but with the button numbers you collected from jstest:

  • a: ❎
  • b: πŸ…ΎοΈ
  • x: πŸ…ΎοΈ
  • y: ❎
  • start: pause/options menu
  • dpup: ⬆️
  • dpdown: ⬇️
  • dpleft: β¬…
  • dpright: ➑

Finally, put it all together! Here's what mine looks like, with funky spaces in the name and all buttons mapped: (note how the axes are expressed as -a1, +a1, -a0, +a0)

030000001f08000001e4000010010000,USB gamepad           ,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,lefttrigger:b6,righttrigger:b7,

Drop that into your sdl_controllers.txt, and it should map successfully. Fire up Pico-8 in a separate terminal window, and then check the log. You should see something like this towards the end:

If it was unsuccessful, it will look like this:

Good luck! πŸ˜ƒ

P#79379 2020-07-16 04:53 ( Edited 2020-07-28 08:34)

[ :: Read More :: ]

Ran into this on MacOS Mojave. If you put a '.' in the filename when you export binaries, the unzipped app will launch just fine, but the zipped one won't.

I made a quick video:
https://youtu.be/NZHUZV4gLGU

P#79352 2020-07-15 14:40 ( Edited 2020-07-15 14:42)

[ :: Read More :: ]

Cart #mozonogozi-0 | 2020-07-14 | Code ▽ | Embed ▽ | No License
19

Hi, friends!

I've just finished my first ever video game!

I just want to thank this entire community for existing and being so helpful and friendly. I discovered Pico-8 in April; at the peak of COVID-19 hitting my hometown, and in the depths of a massive depression brought on by isolation/lack of work/personal losses from the pandemic. It's been a lifelong dream to make a game, but I never thought I'd ever actually accomplish it, and making a little progress on this project each day feels like one of the few things that has really kept me going. So, thank you all!!!

Special thanks to @Liquidream for leading me here in the first place, and being kind enough to do some playtesting and providing lots of helpful feedback along the way. Also thanks to @MBoffin for their zine, which got me started, and for feedback in the forums when I was trying to figure out managing game state.

Also, I have a resprite with (better?) music up on itch.io:
https://ridgek.itch.io/killer-kegs

I think I'm here to stay! On to the next one!

P#79308 2020-07-14 11:00 ( Edited 2020-07-14 11:04)